using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;

namespace MonsterNet
{
	/// <summary>
	/// Location info per computer.
	/// </summary>
	[Serializable]
	public class MNLocation
	{
		private const string _filename = @"MNLocation" + MNGlobal.kMonsterNETFileExtension;
		
		private string _name;
		private bool _manualPath;
		private string _path;		
		private string _portablePath;
		private MNFSObjectLocation _location;
		private SerializableDictionary<string, string> _relocatedPaths; //<directory rootless path, new rootless path>
		private bool _hideIgnored;
		private bool _hidePrivate;
		private bool _deleteFromPortable;
		private bool _removeUsername;
		
		private int _backupAutoDeleteCount; // if > 0 this many files will be kept and the oldest deleted. zero all are kept.
			
		#region properties

		public string Name {
			get {
				return this._name;
			}
			set {
				_name = value;
			}
		}
		
		public static string Savefilename {
			get {
				return _filename;
			}
		}

		public bool ManualPath {
			get {
				return this._manualPath;
			}
			set {
				_manualPath = value;
			}
		}
		
		public string Path {
			get {
				return this._path;
			}
			set {
				_path = value;
			}
		}
	
		public string PortablePath {
			get {
				return this._portablePath;
			}
			set {
				_portablePath = value;
			}
		}
		
		public MNFSObjectLocation CurrentLocation {
			get {
				return this._location;
			}
			set {
				_location = value;
			}
		}
		
		public MNFSObjectLocation OppositeLocation {
			get {
				return GetOppositeLocation(this._location);
			}
		}
		
		public SerializableDictionary<string, string> RelocatedPaths {
			get {
				return _relocatedPaths;
			}
		}
		
		public bool DeleteFromPortable {
			get {
				return this._deleteFromPortable;
			}
			set {
				_deleteFromPortable = value;
			}
		}

		public bool HideIgnored {
			get {
				return this._hideIgnored;
			}
			set {
				_hideIgnored = value;
			}
		}

		public bool HidePrivate {
			get {
				return this._hidePrivate;
			}
			set {
				_hidePrivate = value;
			}
		}
				
		public int BackupAutoDeleteCount {
			get {
				return this._backupAutoDeleteCount;
			}
			set {
				_backupAutoDeleteCount = value;
			}
		}
		
		public bool RemoveUsername {
			get {
				return this._removeUsername;
			}
			set {
				_removeUsername = value;
			}
		}
		
		#endregion
		
		#region Constructor
		
		public MNLocation ()
		{
			_location = MNFSObjectLocation.NumberOfLocations;
			_relocatedPaths = new SerializableDictionary<string, string> ();
			_hideIgnored = false;
			_hidePrivate = false;
			_deleteFromPortable = true;
			_backupAutoDeleteCount = 5;
			_removeUsername = false;
		}
		
		#endregion
		
		public static MNFSObjectLocation GetOppositeLocation (MNFSObjectLocation location)
		{
			if (location == MNFSObjectLocation.Destination) {
				return MNFSObjectLocation.Source;
			} else {
				return MNFSObjectLocation.Destination;
			}
		}
		
		/// <summary>
		/// Backups of the file at the given path name and auto deletes any redundant backups
		/// </summary>
		/// <param name="pathname">
		/// A <see cref="System.String"/> file to backup
		/// </param>
		public void BackupContentsFile (string pathname)
		{
			string backupContentsPath = MNGlobal.DefaultDirectory ();
			
			//copy the contents file.
			DateTime backupDate = DateTime.Now;
			string toPathname = string.Format ("{0}{1}{2}{3}{4}{5}", backupDate.Year, backupDate.Month, backupDate.Day, backupDate.Hour, backupDate.Minute, backupDate.Second);
			toPathname = string.Format (@"Backup({0}) {1}", toPathname, MNGlobal.kDefaultContentsFileName);
			toPathname = MNGlobal.CombinePathAndFilename (backupContentsPath, toPathname);
			try {
				System.IO.File.Copy (pathname, toPathname, true);
			} catch (Exception ex) {
				//TODO: warning contents not backed up.
				Console.WriteLine (ex.ToString ());
			}
			
			//delete old backups, only keep BackupAutoDeleteCount number contents backups.
			Dictionary<string, DateTime> files = BackupFiles ();
			
			if (BackupAutoDeleteCount > 0 && files.Count > BackupAutoDeleteCount) {
				string OldestBackupFilename = string.Empty;
				DateTime OldestBackupFileDate = DateTime.Now;
				
				foreach (KeyValuePair<string, DateTime> kvp in files) {
					if (kvp.Value < OldestBackupFileDate) {
						OldestBackupFilename = kvp.Key;
						OldestBackupFileDate = kvp.Value;
					}
				}
				
				if (OldestBackupFilename != string.Empty) {
					BackupDelete (OldestBackupFilename);
				}
			}
		}
		
		public void BackupDelete(string backupFilename) {
			try {
				System.IO.File.Delete (MNGlobal.CombinePathAndFilename (MNGlobal.DefaultDirectory (), backupFilename));
			} catch (Exception ex) {
				//TODO: warn about to many backups and unable to delete?
				Console.WriteLine (ex.ToString ());
			}			
		}
		
		public void RestoreBackup (string backupFilename)
		{
			try 
			{
				System.IO.File.Copy (MNGlobal.CombinePathAndFilename (MNGlobal.DefaultDirectory (), backupFilename), 
					MNGlobal.CombinePathAndFilename (this.PortablePath, MNGlobal.kDefaultContentsFileName), true);
			} catch (Exception ex) {
				//TODO: warn the restore didn't work
				Console.WriteLine (ex.ToString ());
			}
		}
		
		/// <summary>
		/// A dictionary of contents file backups 
		/// </summary>
		/// <returns>
		/// A <see cref="Dictionary<System.String, DateTime>"/> Backup file name, backup file write date
		/// </returns>
		public Dictionary<string, DateTime> BackupFiles ()
		{
			Dictionary<string, DateTime> files = new Dictionary<string, DateTime> ();
			
			foreach (string aFile in Directory.GetFiles (MNGlobal.DefaultDirectory ())) {
				if (aFile.EndsWith (MNGlobal.kDefaultContentsFileName)) {
					//the file is a backup contents file.
					DateTime creationTime = System.IO.File.GetLastWriteTime (aFile);
					
					files.Add (System.IO.Path.GetFileName (aFile), creationTime);
				}
			}
			return files;
		}		
	}
}

